package com.zenithmind.document.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.document.mapper.DocumentTagMapper;
import com.zenithmind.document.pojo.domain.DocumentTag;
import com.zenithmind.document.pojo.dto.DocumentTagCreateDTO;
import com.zenithmind.document.pojo.dto.DocumentTagUpdateDTO;
import com.zenithmind.document.pojo.query.DocumentTagQueryDTO;
import com.zenithmind.document.pojo.vo.DocumentTagVO;
import com.zenithmind.document.service.DocumentTagService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 文档标签服务实现类
 * 遵循单一职责原则：专注于标签管理
 * 遵循依赖倒置原则：依赖抽象接口而不是具体实现
 * 
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DocumentTagServiceImpl extends ServiceImpl<DocumentTagMapper, DocumentTag> implements DocumentTagService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DocumentTagVO createTag(DocumentTagCreateDTO createDTO) {
        log.info("创建标签: name={}", createDTO.getName());
        
        // 检查标签是否已存在
        if (checkTagExists(createDTO.getName())) {
            throw new RuntimeException("标签已存在");
        }
        
        DocumentTag tag = new DocumentTag();
        BeanUtils.copyProperties(createDTO, tag);
        tag.setCreateTime(LocalDateTime.now());
        tag.setUpdateTime(LocalDateTime.now());
        
        save(tag);
        
        return convertToVO(tag);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateTag(String id, DocumentTagUpdateDTO updateDTO) {
        log.info("更新标签: id={}", id);
        
        DocumentTag tag = getById(id);
        if (tag == null) {
            throw new RuntimeException("标签不存在");
        }
        
        // 如果修改名称，检查新名称是否已存在
        if (updateDTO.getName() != null && !updateDTO.getName().equals(tag.getName())) {
            if (checkTagExists(updateDTO.getName())) {
                throw new RuntimeException("标签名称已存在");
            }
        }
        
        BeanUtils.copyProperties(updateDTO, tag);
        tag.setUpdateTime(LocalDateTime.now());
        
        return updateById(tag);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteTag(String id) {
        log.info("删除标签: id={}", id);
        
        // 检查标签是否被使用
        if (baseMapper.checkTagInUse(id)) {
            throw new RuntimeException("标签正在使用中，无法删除");
        }
        
        return removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDeleteTags(List<String> ids) {
        log.info("批量删除标签: ids={}", ids);
        
        // 检查标签是否被使用
        List<String> inUseTags = baseMapper.checkTagsInUse(ids);
        if (!inUseTags.isEmpty()) {
            throw new RuntimeException("以下标签正在使用中，无法删除: " + inUseTags);
        }
        
        return removeByIds(ids);
    }

    @Override
    public IPage<DocumentTagVO> getTagPage(DocumentTagQueryDTO queryDTO) {
        log.info("分页查询标签");
        
        Page<DocumentTagVO> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        
        return baseMapper.selectTagPageWithDetails(page, queryDTO);
    }

    @Override
    public DocumentTagVO getTagDetail(String id) {
        log.info("获取标签详情: id={}", id);
        
        DocumentTag tag = getById(id);
        if (tag == null) {
            throw new RuntimeException("标签不存在");
        }
        
        return convertToVO(tag);
    }

    @Override
    public DocumentTagVO getTagByName(String name) {
        log.info("根据名称获取标签: name={}", name);
        
        return baseMapper.selectTagByName(name);
    }

    @Override
    public List<DocumentTagVO> getAllTags() {
        log.info("获取所有标签");
        
        return baseMapper.selectAllTags();
    }

    @Override
    public List<DocumentTagVO> searchTags(String keyword, Integer limit) {
        log.info("搜索标签: keyword={}, limit={}", keyword, limit);
        
        return baseMapper.searchTags(keyword, limit);
    }

    @Override
    public List<DocumentTagVO> getHotTags(Integer limit) {
        log.info("获取热门标签: limit={}", limit);
        
        return baseMapper.selectHotTags(limit);
    }

    @Override
    public List<DocumentTagVO> getLatestTags(Integer limit) {
        log.info("获取最新标签: limit={}", limit);
        
        return baseMapper.selectLatestTags(limit);
    }

    @Override
    public List<DocumentTagVO> getUserTags(String userId, Integer limit) {
        log.info("获取用户标签: userId={}, limit={}", userId, limit);
        
        return baseMapper.selectUserTags(userId, limit);
    }

    @Override
    public List<DocumentTagVO> getDocumentTags(String documentId) {
        log.info("获取文档标签: documentId={}", documentId);
        
        return baseMapper.selectDocumentTags(documentId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addTagsToDocument(String documentId, List<String> tagNames, String userId) {
        log.info("为文档添加标签: documentId={}, tagNames={}", documentId, tagNames);
        
        // 创建或获取标签
        List<DocumentTagVO> tags = batchCreateOrGetTags(tagNames, userId);
        List<String> tagIds = tags.stream().map(DocumentTagVO::getId).collect(Collectors.toList());
        
        return baseMapper.addTagsToDocument(documentId, tagIds, userId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeTagsFromDocument(String documentId, List<String> tagNames) {
        log.info("从文档移除标签: documentId={}, tagNames={}", documentId, tagNames);
        
        return baseMapper.removeTagsFromDocument(documentId, tagNames) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean replaceDocumentTags(String documentId, List<String> tagNames, String userId) {
        log.info("替换文档标签: documentId={}, tagNames={}", documentId, tagNames);
        
        // 先移除所有标签
        baseMapper.removeAllTagsFromDocument(documentId);
        
        // 再添加新标签
        if (!tagNames.isEmpty()) {
            return addTagsToDocument(documentId, tagNames, userId);
        }
        
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchAddTagsToDocuments(List<String> documentIds, List<String> tagNames, String userId) {
        log.info("批量为文档添加标签: documentIds={}, tagNames={}", documentIds, tagNames);
        
        // 创建或获取标签
        List<DocumentTagVO> tags = batchCreateOrGetTags(tagNames, userId);
        List<String> tagIds = tags.stream().map(DocumentTagVO::getId).collect(Collectors.toList());
        
        return baseMapper.batchAddTagsToDocuments(documentIds, tagIds, userId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchRemoveTagsFromDocuments(List<String> documentIds, List<String> tagNames) {
        log.info("批量从文档移除标签: documentIds={}, tagNames={}", documentIds, tagNames);
        
        return baseMapper.batchRemoveTagsFromDocuments(documentIds, tagNames) > 0;
    }

    @Override
    public Object getTagUsageStatistics(String tagId) {
        log.info("获取标签使用统计: tagId={}", tagId);
        
        return baseMapper.selectTagUsageStatistics(tagId);
    }

    @Override
    public List<Object> getTagCloudData(Integer limit) {
        log.info("获取标签云数据: limit={}", limit);
        
        return baseMapper.selectTagCloudData(limit);
    }

    @Override
    public List<DocumentTagVO> getRelatedTags(String tagId, Integer limit) {
        log.info("获取相关标签: tagId={}, limit={}", tagId, limit);
        
        return baseMapper.selectRelatedTags(tagId, limit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean mergeTags(String sourceTagId, String targetTagId) {
        log.info("合并标签: sourceTagId={}, targetTagId={}", sourceTagId, targetTagId);
        
        return baseMapper.mergeTags(sourceTagId, targetTagId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean splitTag(String tagId, List<String> newTagNames) {
        log.info("拆分标签: tagId={}, newTagNames={}", tagId, newTagNames);
        
        return baseMapper.splitTag(tagId, newTagNames) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean renameTag(String tagId, String newName) {
        log.info("重命名标签: tagId={}, newName={}", tagId, newName);
        
        // 检查新名称是否已存在
        if (checkTagExists(newName)) {
            throw new RuntimeException("标签名称已存在");
        }
        
        return baseMapper.renameTag(tagId, newName) > 0;
    }

    @Override
    public Boolean checkTagExists(String name) {
        log.info("检查标签是否存在: name={}", name);
        
        return baseMapper.checkTagExists(name);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DocumentTagVO createOrGetTag(String name, String userId) {
        log.info("创建或获取标签: name={}", name);
        
        DocumentTagVO existingTag = getTagByName(name);
        if (existingTag != null) {
            return existingTag;
        }
        
        DocumentTag tag = DocumentTag.createTag(name, userId);
        save(tag);
        
        return convertToVO(tag);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<DocumentTagVO> batchCreateOrGetTags(List<String> names, String userId) {
        log.info("批量创建或获取标签: names={}", names);
        
        return names.stream()
                .map(name -> createOrGetTag(name, userId))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getTagSuggestions(String input, Integer limit) {
        log.info("获取标签建议: input={}, limit={}", input, limit);
        
        return baseMapper.selectTagSuggestions(input, limit);
    }

    @Override
    public List<String> extractTagsFromContent(String content, Integer limit) {
        log.info("从内容提取标签: limit={}", limit);

        if (!StringUtils.hasText(content)) {
            return List.of();
        }

        // 简单的关键词提取算法
        List<String> extractedTags = new ArrayList<>();

        // 1. 分词并过滤
        String[] words = content.replaceAll("[^\\u4e00-\\u9fa5a-zA-Z0-9\\s]", " ")
                               .split("\\s+");

        Map<String, Integer> wordCount = new HashMap<>();
        for (String word : words) {
            if (word.length() >= 2 && word.length() <= 10) {
                wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
            }
        }

        // 2. 按频率排序并取前N个
        extractedTags = wordCount.entrySet().stream()
                .filter(entry -> entry.getValue() >= 2) // 至少出现2次
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .limit(limit != null ? limit : 10)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        // TODO: 集成NLP服务进行更智能的标签提取

        return extractedTags;
    }

    @Override
    public List<Object> getTagTrends(Integer days, Integer limit) {
        log.info("获取标签趋势: days={}, limit={}", days, limit);
        
        return baseMapper.selectTagTrends(days, limit);
    }

    @Override
    public List<Object> getTagCategories() {
        log.info("获取标签分类");
        
        return baseMapper.selectTagCategories();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setTagCategory(String tagId, String categoryId) {
        log.info("设置标签分类: tagId={}, categoryId={}", tagId, categoryId);
        
        return baseMapper.setTagCategory(tagId, categoryId) > 0;
    }

    @Override
    public List<DocumentTagVO> getTagsByCategory(String categoryId, Integer limit) {
        log.info("获取分类下的标签: categoryId={}, limit={}", categoryId, limit);
        
        return baseMapper.selectTagsByCategory(categoryId, limit);
    }

    @Override
    public Object exportTags(DocumentTagQueryDTO queryDTO) {
        log.info("导出标签数据");
        
        return baseMapper.exportTags(queryDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer importTags(List<DocumentTagCreateDTO> tags) {
        log.info("导入标签数据: size={}", tags.size());
        
        List<DocumentTag> tagEntities = tags.stream()
                .map(dto -> {
                    DocumentTag tag = new DocumentTag();
                    BeanUtils.copyProperties(dto, tag);
                    tag.setCreateTime(LocalDateTime.now());
                    tag.setUpdateTime(LocalDateTime.now());
                    return tag;
                })
                .collect(Collectors.toList());
        
        return baseMapper.batchInsertTags(tagEntities);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer cleanupUnusedTags() {
        log.info("清理未使用的标签");
        
        return baseMapper.cleanupUnusedTags();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean syncTagStatistics() {
        log.info("同步标签统计");
        
        return baseMapper.syncTagStatistics() > 0;
    }

    @Override
    public List<Object> getTagUsageHistory(String tagId, Integer limit) {
        log.info("获取标签使用历史: tagId={}, limit={}", tagId, limit);
        
        return baseMapper.selectTagUsageHistory(tagId, limit);
    }

    @Override
    public List<DocumentTagVO> recommendTagsToUser(String userId, Integer limit) {
        log.info("推荐标签给用户: userId={}, limit={}", userId, limit);
        
        return baseMapper.selectRecommendedTagsForUser(userId, limit);
    }

    @Override
    public List<Object> getTagCooccurrenceAnalysis(String tagId, Integer limit) {
        log.info("获取标签共现分析: tagId={}, limit={}", tagId, limit);
        
        return baseMapper.selectTagCooccurrenceAnalysis(tagId, limit);
    }

    /**
     * 转换为VO对象
     */
    private DocumentTagVO convertToVO(DocumentTag tag) {
        DocumentTagVO vo = new DocumentTagVO();
        BeanUtils.copyProperties(tag, vo);
        return vo;
    }
}
